/****************************************************************************
 * Copyright (c) 2006 Parity Communications, Inc.
 *
 * This program and the accompanying materials are made
 * available under the terms of the Eclipse Public License 2.0
 * which is available at https://www.eclipse.org/legal/epl-2.0/
 *
 * Contributors:
 *     Sergey Yakovlev - initial API and implementation
 *
 * SPDX-License-Identifier: EPL-2.0
 *****************************************************************************/
package org.eclipse.ecf.internal.provider.rss.container;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;
import java.util.Date;

import org.eclipse.ecf.core.util.Trace;
import org.eclipse.ecf.internal.provider.rss.RssDebugOptions;
import org.eclipse.ecf.internal.provider.rss.RssPlugin;
import org.eclipse.ecf.internal.provider.rss.http.HttpRequest;
import org.eclipse.ecf.internal.provider.rss.http.HttpResponse;
import org.eclipse.ecf.provider.comm.tcp.ISocketAcceptHandler;
import org.eclipse.ecf.provider.comm.tcp.Server;
import org.eclipse.ecf.provider.generic.SOContainerGroup;

/**
 * 
 */
public class RssServerSOContainerGroup extends SOContainerGroup implements ISocketAcceptHandler {

	private static final String PRODUCT_NAME = "ECF RSS Server/0.0.1";
	private static final String DEFAULT_GROUP_NAME = RssServerSOContainerGroup.class.getName();

	protected int port;
	protected Server listener;
	protected ThreadGroup threadGroup;
	private boolean isOnTheAir = false;

	/**
	 * The constructors
	 * @param port 
	 */
	public RssServerSOContainerGroup(int port) {
		this(DEFAULT_GROUP_NAME, null, port);
	}

	public RssServerSOContainerGroup(String name, int port) {
		this(name, null, port);
	}

	public RssServerSOContainerGroup(String name, ThreadGroup group, int port) {
		super(name);
		threadGroup = group;
		this.port = port;
	}

	protected void trace(String msg) {
		Trace.trace(RssPlugin.PLUGIN_ID, RssDebugOptions.DEBUG, msg);
	}

	protected void dumpStack(String msg, Throwable e) {
		Trace.catching(RssPlugin.PLUGIN_ID, RssDebugOptions.EXCEPTIONS_CATCHING, this.getClass(), "", e);
	}

	public synchronized void putOnTheAir() throws IOException {
		trace("Group at port " + port + " on the air");
		listener = new Server(threadGroup, port, this);
		port = listener.getLocalPort();
		isOnTheAir = true;
	}

	public synchronized boolean isOnTheAir() {
		return isOnTheAir;
	}

	public void handleAccept(Socket socket) throws Exception {
		final HttpRequest request = new HttpRequest(socket.getInputStream());
		final RssServerSOContainer con = (RssServerSOContainer) get(String.valueOf(port));
		if (con == null) {
			throw new IOException("Container for port " + port + " not found!");
		}
		trace("Found container: " + con.getID().getName() + " for target " + request.getURLString());
		String body = "";
		int code = HttpResponse.SERVER_ERROR;
		String path = request.getPath();
		// Tests whether this abstract pathname is absolute.
		path = path.startsWith("/") ? path.substring(1) : path;
		final File feedFile = new File(path);
		Date lastModified = new Date();
		if (feedFile.exists() && feedFile.isFile()) {
			trace("Found feed file: " + feedFile.getAbsolutePath());
			code = HttpResponse.OK;
			body = readFileToString(feedFile);
			lastModified = new Date(feedFile.lastModified());
		} else {
			code = HttpResponse.NOT_FOUND;
		}
		// Create connect response and send it back
		final HttpResponse response = new HttpResponse(code, body);
		if (body != null && body.length() > 0) {
			response.setHeader("Connection", "close");
			response.setHeader("Content-Type", "text/xml");
			response.setHeader("Server", PRODUCT_NAME);
			response.setDateHeader("Last-Modified", lastModified);
		}
		response.writeToStream(socket.getOutputStream());
	}

	private String readFileToString(File file) throws IOException {
		final FileInputStream in = new FileInputStream(file);
		final ByteArrayOutputStream out = new ByteArrayOutputStream();
		int n;
		final byte buffer[] = new byte[8192];
		while ((n = in.read(buffer, 0, buffer.length)) > -1) {
			out.write(buffer, 0, n);
			out.flush();
		}
		return out.toString();
	}

	public synchronized void takeOffTheAir() {
		if (listener != null) {
			trace("Taking " + getName() + " on the air.");
			try {
				listener.close();
			} catch (final IOException e) {
				dumpStack("Exception in closeListener", e);
			}
			listener = null;
		}
		isOnTheAir = false;
	}

	public int getPort() {
		return port;
	}

	public String toString() {
		return super.toString() + ";port:" + port;
	}
}
